/** ****************************************************************************
* @defgroup BSP BSP(Board Support Package)
* @brief BSP(Board Support Package)层定义
* @addtogroup BSP
* @{
*******************************************************************************/

#include "stdinc.h"


void GPIN_Config(GPIO_TypeDef* port, uint8_t pin, uint8_t cfg) {
	(cfg & BV(2)) ? (port->DDR |= BV(pin)) : (port->DDR &= ~BV(pin));
	(cfg & BV(1)) ? (port->CR1 |= BV(pin)) : (port->CR1 &= ~BV(pin));
	(cfg & BV(0)) ? (port->CR2 |= BV(pin)) : (port->CR2 &= ~BV(pin));
}

int isValidEntry(uint16_t entry) {
	uint16_t opCode 		= *((uint16_t*)entry);
    uint16_t entryFunc 	= *((uint16_t*)entry+2);
    return (opCode == 0x8200 ) &&
           ISBETWEEN(entryFunc, FLASH_PROGRAM_START_PHYSICAL_ADDRESS, FLASH_PROGRAM_END_PHYSICAL_ADDRESS);
}

// 要跳转到的目标程序中断向量表地址
// ！！！注意：必须使用全局变量，局部变量在汇编中无法访问！！！
static uint16_t _dstIntvecAddress;

void jump2Entry(uint16_t entry) {
    if( !isValidEntry(entry) ) {
		printf("Can't jump to invalid entry: 0x%04X\r\n", entry);
        return;
    }
    printf("Jump to Entry at 0x%04lX ...\r\n", entry);

    // 初始化程序入口地址
	_dstIntvecAddress = entry;
    // 必须先关闭全局中断
    disableInterrupts();

    // 清空堆栈，把SP恢复到程序启动状态
    ASM("LDW X,  SP");
    ASM("LD  A,  $FF");
    ASM("LD  XL, A");
    ASM("LDW SP, X");

    // 跳转到 Flash 中 Bootloader 所在位置
    // 不能使用 JPF 指令，因为它无法用变量指定跳转地址
    ASM("LDW X, _dstIntvecAddress");
    ASM("JP(X)");
}

int isInDebugging() {
	return (RST_GetFlagStatus(RST_FLAG_SWIMF) == SET);
}

bool isAbnormalReboot() {
	bool abnormalReboot = false;
	uint8_t rst = RST->SR;
	printf("RST_FLAG = 0x%02X\r\n", rst);

	if(rst & RST_FLAG_SWIMF) {
		printf("* SWIM reset\r\n");
	}

	if(rst & RST_FLAG_ILLOPF) {
		printf("* Illegal opcode reset\r\n");
		abnormalReboot = true;
		RST_ClearFlag(RST_FLAG_ILLOPF);
	}
	if(rst & RST_FLAG_IWDGF) {
		printf("* Independent watchdog reset\r\n");
		abnormalReboot = true;
		RST_ClearFlag(RST_FLAG_IWDGF);
	}
	if(rst & RST_FLAG_WWDGF) {
		printf("* Window watchdog reset\r\n");
		abnormalReboot = true;
		RST_ClearFlag(RST_FLAG_WWDGF);
	}

	return abnormalReboot;
}


/// @}
